﻿using Developer.Core.FrameWork.GlobalVar;
using Developer.Core.FrameWork.HelpFile;
using Developer.Core.FrameWork.Pollys.Options;
using Microsoft.Extensions.DependencyInjection;
using Polly;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Developer.Core.FrameWork.Pollys.Extensions
{
    /// <summary>
    /// Polly熔断降级扩展类
    /// </summary>
    public static class PollyHttpClientServiceCollectionExtension
    {
        public static IServiceCollection AddPollyHttpClient(this IServiceCollection services, string name, Action<PollyHttpClientOptions> action)
        {
            // 0、是否开启Polly熔断降级
            if (!GlobalVars.Polly)
                return services;

            // 1、构建Polly配置选项
            PollyHttpClientOptions options = new PollyHttpClientOptions();
            action(options);

            // 2、封装降级消息
            var fallbackResponse = new HttpResponseMessage
            {
                Content = new StringContent(options.ResponseMessage),// 降级消息
                StatusCode = HttpStatusCode.GatewayTimeout // 降级状态码
            };

            // 3、配置httpclient
            services.AddHttpClient(name)

            // 4、降级策略
            .AddPolicyHandler(Policy<HttpResponseMessage>
            .HandleInner<Exception>().FallbackAsync(fallbackResponse, async b =>
            {
                // 4.1、降级异常打印
                Console.WriteLine($"服务{name}开始降级，异常消息：{b.Exception.Message}");

                // 4.2、降级后的数据
                Console.WriteLine($"服务{name}降级响应内容：{fallbackResponse.RequestMessage}");

                await Task.CompletedTask;
            }))
            // 5、断路器策略
            .AddPolicyHandler(Policy<HttpResponseMessage>.Handle<Exception>().CircuitBreakerAsync(options.CircuitBreakerOpenFallCount,
            TimeSpan.FromSeconds(options.CircuitBreakerDownTime), (ex, ts) =>
            {
                Console.WriteLine($"服务{name}断路器开启，异常消息：{ex.Exception.Message}");
                Console.WriteLine($"服务{name}断路器开启时间：{ts.TotalSeconds}s");
            }, () =>
            {
                Console.WriteLine($"服务{name}断路器关闭");
            }, () =>
            {
                Console.WriteLine($"服务{name}断路器半开启（时间控制，自动开关）");
            }))
            // 6、重试策略
            .AddPolicyHandler(Policy<HttpResponseMessage>
            .Handle<Exception>()
            .RetryAsync(options.RetryCount)
            )
            // 7、超时策略
            .AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(options.TimeoutTime)));

            return services;
        }
    }
}
